package com.zh.sharding.sale.support.sharding;

import org.apache.shardingsphere.infra.util.exception.ShardingSpherePreconditions;
import org.apache.shardingsphere.sharding.algorithm.sharding.ShardingAutoTableAlgorithmUtil;
import org.apache.shardingsphere.sharding.api.sharding.ShardingAutoTableAlgorithm;
import org.apache.shardingsphere.sharding.api.sharding.standard.PreciseShardingValue;
import org.apache.shardingsphere.sharding.api.sharding.standard.RangeShardingValue;
import org.apache.shardingsphere.sharding.api.sharding.standard.StandardShardingAlgorithm;
import org.apache.shardingsphere.sharding.exception.algorithm.sharding.ShardingAlgorithmInitializationException;

import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
import java.util.Properties;

/**
 * 自定义Orders的分片算法
 * 根据订单的userId 分片
 * @author zhou
 * @date 2023/8/25
 */
public class OrdersShardingAlgorithm implements StandardShardingAlgorithm<Comparable<?>>, ShardingAutoTableAlgorithm {
    static final String SHARDING_COUNT_KEY = "sharding-count";

    private int shardingCount;

    @Override
    public void init(Properties props) {
        this.shardingCount = getShardingCount(props);
    }
    private int getShardingCount(final Properties props) {
        if (!props.containsKey(SHARDING_COUNT_KEY)){
            throw new IllegalArgumentException("Sharding count 没有指定");
        }
        return Integer.parseInt(props.getProperty(SHARDING_COUNT_KEY));
    }

    @Override
    public String doSharding(final Collection<String> availableTargetNames, final PreciseShardingValue<Comparable<?>> shardingValue) {
        //对user_id的值进行hash取模。user_id = shardingValue.getValue()
        String suffix = String.valueOf(hashShardingValue(shardingValue.getValue()) % shardingCount);
        //寻找匹配的tableName
        return ShardingAutoTableAlgorithmUtil.findMatchedTargetName(availableTargetNames, suffix, shardingValue.getDataNodeInfo()).orElse(null);
    }

    @Override
    public Collection<String> doSharding(final Collection<String> availableTargetNames, final RangeShardingValue<Comparable<?>> shardingValue) {
        return availableTargetNames;
    }

    @Override
    public String getType() {
        return "MY_HASH";
    }

    @Override
    public int getAutoTablesAmount() {
        return shardingCount;
    }

    private long hashShardingValue(final Object shardingValue) {
        return Math.abs((long) shardingValue.hashCode());
    }
}
